#ifndef CONVERUTF_HPP
#define CONVERUTF_HPP

#include "convertutf.h"

#define IS_UTF(t) (sizeof(t) == 4 || sizeof(t) == 2 || sizeof(t) == 1)

template <class UTFT>
size_t utflen(const UTFT *str)
{
	size_t l;
	for (l = 0;*str != 0;l++)
		str++;
	return l;
}

template <class UTFT>
UTFT *utfcpy(UTFT *dest, const UTFT *src)
{
	UTFT *start = dest;

	while (*dest++ = *src++);

	return start;
}

template <class UTFT1, class UTFT2>
int ConvertUTF(const UTFT1 *source, UTFT2 *&dest, const size_t length = 0)
{
	const size_t ts1 = sizeof(UTFT1), ts2 = sizeof(UTFT2);

	if (ts1 == ts2 || !(ts1 == 1 || ts1 == 2 || ts1 == 4) || !(ts2 == 1 || ts2 == 2 || ts2 == 4) || source == NULL)
		return -1;

	const size_t len = utflen(source);
	size_t buflen;
	UTFT2 *pEnd;

	if (length == 0) {
		switch (ts2) {
			case 1:
				buflen = len << 2;
			break;
			case 2:
				buflen = len << 1;
			break;
			case 4:
				buflen = len;
			break;
		}
		dest = new UTFT2 [buflen + 1];
	}
	else
		buflen = length - 1;

	if (dest == NULL)
		return -1;

	pEnd = dest;

	if (ts1 == 1 && ts2 == 2) {
		if (ConvertUTF8toUTF16((const UTF8 **) &source, ((UTF8 *) source) + len, (UTF16 **) &pEnd, ((UTF16 *) dest) + buflen, strictConversion) == conversionOK)
			*pEnd = 0;
		else
			return 1;
	}
	else if (ts1 == 1 && ts2 == 4) {
		if (ConvertUTF8toUTF32((const UTF8 **) &source, ((UTF8 *) source) + len, (UTF32 **) &pEnd, ((UTF32 *) dest) + buflen, strictConversion) == conversionOK)
			*pEnd = 0;
		else
			return 1;
	}
	else if (ts1 == 2 && ts2 == 1) {
		if (ConvertUTF16toUTF8((const UTF16 **) &source, ((UTF16 *) source) + len, (UTF8 **) &pEnd, ((UTF8 *) dest) + buflen, strictConversion) == conversionOK)
			*pEnd = 0;
		else
			return 1;
	}
	else if (ts1 == 2 && ts2 == 4) {
		if (ConvertUTF16toUTF32((const UTF16 **) &source, ((UTF16 *) source) + len, (UTF32 **) &pEnd, ((UTF32 *) dest) + buflen, strictConversion) == conversionOK)
			*pEnd = 0;
		else
			return 1;
	}
	else if (ts1 == 4 && ts2 == 1) {
		if (ConvertUTF32toUTF8((const UTF32 **) &source, ((UTF32 *) source) + len, (UTF8 **) &pEnd, ((UTF8 *) dest) + buflen, strictConversion) == conversionOK)
			*pEnd = 0;
		else
			return 1;
	}
	else if (ts1 == 4 && ts2 == 2) {
		if (ConvertUTF32toUTF16((const UTF32 **) &source, ((UTF32 *) source) + len, (UTF16 **) &pEnd, ((UTF16 *) dest) + buflen, strictConversion) == conversionOK)
			*pEnd = 0;
		else
			return 1;
	}

	return 0;
}

#endif
